/**
 * <p>Title: Cell Class</p>
 * <p>Description: CS 343 Project</p>
 * @author Quintin Stolpe
 * @email quintin.stolpe@my.uwrf.edu
 * @date Dec 3 2012
*/

package maze;


public class Graph
{

	Object[][] elementArray;
	int[][] myMaze;

	public void makeGraph(int[][] maze)
	{
		myMaze = maze;
		elementArray = new Object[maze.length][maze[0].length];

		Node node = null;

		// find all intersections, which will be the nodes
		for (int y = 1; y < maze[0].length - 1; y++)
		{
			for (int x = 1; x < maze.length - 1; x++)
			{
				if (maze[x][y] != Maze.WALL)
				{

					int numWalls =
						maze[x
							+ 1][y]
							+ maze[x
							- 1][y]
							+ maze[x][y
							+ 1]
							+ maze[x][y
							- 1];

					if (numWalls < 2)
					{
						node = new Node(x, y);
						elementArray[x][y] = node;
					}
				}
			}
		}

		// recursively connect all the nodes together with edges
		if (node != null)
		{
			connectNodes(node);
		}

		printGraph();
	}

	// recursively explore in all directions from a node
	private void connectNodes(Node node)
	{
		System.out.println(
			"Enter connectNodes (" + node.myX + "," + node.myY + ")");
		startTraverse(-1, 0, node);
		startTraverse(1, 0, node);
		startTraverse(0, -1, node);
		startTraverse(0, 1, node);
		System.out.println(
			"Exit connectNodes (" + node.myX + "," + node.myY + ")");

	}

	// see if there is an edge in this direction from the node
	// if so, start an edge
	private void startTraverse(int dx, int dy, Node node)
	{
		if (isEmpty(node.myX + dx, node.myY + dy))
		{
			// if there can be an edge here but isn't, then add it
			Edge edge = new Edge();
			edge.startNode = node;
			Segment seg = new Segment(node.myX, node.myY, dx!=0);
			edge.addSegment(seg);
			node.addEdge(edge);
			traverse(node.myX + dx, node.myY + dy, dx, dy, edge, seg);
		}
		else if (elementArray[node.myX + dx][node.myY + dy] instanceof Edge)
		{
			// if an edge is already here, reverse it and add it.
			Edge edge = (Edge) elementArray[node.myX + dx][node.myY + dy];
			Edge newEdge = new Edge();
			newEdge.startNode = edge.endNode;
			newEdge.endNode = edge.startNode;
			newEdge.segmentsVector = edge.segmentsVector;
			node.addEdge(newEdge);
		}
	}

	private boolean isEmpty(int x, int y)
	{
		return (
			x >= 0
				&& x < myMaze.length
				&& y >= 0
				&& y < myMaze[0].length
				&& myMaze[x][y] != Maze.WALL
				&& elementArray[x][y] == null);
	}

	private boolean isNode(int x, int y)
	{
		return (
			x >= 0
				&& x < myMaze.length
				&& y >= 0
				&& y < myMaze[0].length
				&& myMaze[x][y] != Maze.WALL
				&& elementArray[x][y] != null
				&& (elementArray[x][y] instanceof Node));
	}

	public void traverse(int x, int y, int dx, int dy, Edge edge, Segment seg)
	{
		elementArray[x][y] = edge;
		if (isNode(x + dx, y + dy))
		{
			// end of edge
			edge.endNode = (Node) elementArray[x + dx][y + dy];
			seg.setEnd(x+dx, y+dy);
		
			connectNodes(edge.endNode);
			return;
		}

		if (isEmpty(x + dx, y + dy))
		{
			// segment continues
			traverse(x + dx, y + dy, dx, dy, edge, seg);
			return;
		}

		// this is the end of the segment
		seg.setEnd(x,y);
	
		if (dx != 0)
		{
			if (myMaze[x][y - 1] != Maze.WALL)
			{
				dx = 0;
				dy = -1;
				seg = new Segment(x, y, false);
			}
			else if (myMaze[x][y + 1] != Maze.WALL)
			{
				dx = 0;
				dy = 1;
				seg = new Segment(x, y, false);
			}
			else
			{
				System.out.println("Error traversing: " + x + "," + y);
				return;
			}
		}
		else
		{
			if (myMaze[x - 1][y] != Maze.WALL)
			{
				dx = -1;
				dy = 0;
				seg = new Segment(x, y, true);
			}
			else if (myMaze[x + 1][y] != Maze.WALL)
			{
				dx = 1;
				dy = 0;
				seg = new Segment(x, y, true);
			}
			else
			{
				System.out.println("Error traversing: " + x + "," + y);
				return;
			}
		}

		edge.addSegment(seg);
		traverse(x, y, dx, dy, edge, seg);

	}

	private void printGraph()
	{
		for (int x = 0; x < elementArray.length; x++)
		{
			for (int y = 0; y < elementArray[x].length; y++)
			{
				Object obj = elementArray[x][y];
				if (obj == null)
				{
					System.out.print(" ");
				}
				else if (obj instanceof Node)
				{
					System.out.print("+");
				}
				else if (obj instanceof Edge)
				{
					System.out.print("|");
				}

			}
			System.out.println();
		}
	}

	public Node getNode(int x, int y)
	{
		Object obj = elementArray[x][y];

		if (obj instanceof Node)
		{
			return (Node) obj;
		}

		return null;
	}

	public Edge getEdge(int x, int y)
	{
		Object obj = elementArray[x][y];

		if (obj instanceof Edge)
		{
			return (Edge) obj;
		}
		else if (obj instanceof Node)
		{
			
			return (Edge)(((Node)obj).outEdgesVector.firstElement());
		}

		return null;
	}

}
